`include "./AdamRiscv/define.vh"

module alu(
    input  wire[3:0]     alu_ctrl,
    input  wire[31:0]    op_A,
    input  wire[31:0]    op_B,
    output reg[31:0]     alu_o,
    output wire          br_mark,
    input wire[31:0] ex_r_matrix_mopa[3:0],
    output wire [31:0] matrix_mopa_o [3:0]    
);

reg[31:0] matrix_line_0;
reg[31:0] matrix_line_1;
reg[31:0] matrix_line_2;
reg[31:0] matrix_line_3;
assign br_mark = (alu_ctrl == `JUMP)? 1 :
                 (alu_ctrl == `NOTEQ || alu_ctrl == `SLT || alu_ctrl == `SLTU)?
                 (alu_o != 0) : (alu_o == 0);
 
always @(alu_ctrl, op_A, op_B) begin
    case (alu_ctrl)
        `AND        : alu_o = op_A & op_B;           
        `OR         : alu_o = op_A | op_B;           
        `ADD,`JUMP  : alu_o = op_A + op_B;           
        `SUB,`NOTEQ : alu_o = op_A - op_B;           
        `XOR        : alu_o = op_A ^ op_B;           
        `SLT,`SGE   : alu_o = ($signed(op_A)) < ($signed(op_B)) ? 32'b1 : 32'b0;   
        `SLTU,`SGEU : alu_o = op_A < op_B ? 32'b1 : 32'b0;   
        `SLL        : alu_o = op_A << op_B[4:0];
        `SRL        : alu_o = op_A >> op_B[4:0];
        `SRA        : alu_o = ($signed(op_A)) >>> op_B[4:0];
	`MOPA       : begin
			matrix_line_3 = {
			ex_r_matrix_mopa[3][31:24] + op_A[31:24] * op_B[31:24],
			ex_r_matrix_mopa[3][23:16] + op_A[23:16] * op_B[31:24],
			ex_r_matrix_mopa[3][15:8] + op_A[15:8] * op_B[31:24],
			ex_r_matrix_mopa[3][7:0] + op_A[7:0] * op_B[31:24]
			};
			matrix_line_2 = {
			ex_r_matrix_mopa[2][31:24] + op_A[31:24] * op_B[23:16],
			ex_r_matrix_mopa[2][23:16] + op_A[23:16] * op_B[23:16],
			ex_r_matrix_mopa[2][15:8] + op_A[15:8] * op_B[23:16],
			ex_r_matrix_mopa[2][7:0] + op_A[7:0] * op_B[23:16]
			};
			matrix_line_1 = {
			ex_r_matrix_mopa[1][31:24] + op_A[31:24] * op_B[15:8],
			ex_r_matrix_mopa[1][23:16] + op_A[23:16] * op_B[15:8],
			ex_r_matrix_mopa[1][15:8] + op_A[15:8] * op_B[15:8],
			ex_r_matrix_mopa[1][7:0] + op_A[7:0] * op_B[15:8]
			};
			matrix_line_0 = {
			ex_r_matrix_mopa[0][31:24] + op_A[31:24] * op_B[7:0],
			ex_r_matrix_mopa[0][23:16] + op_A[23:16] * op_B[7:0],
			ex_r_matrix_mopa[0][15:8] + op_A[15:8] * op_B[7:0],
			ex_r_matrix_mopa[0][7:0] + op_A[7:0] * op_B[7:0]
			};
			alu_o = 0;
	
	end
        default: begin
		alu_o = 0;
		matrix_line_0 = 0;
		matrix_line_1 = 0;
		matrix_line_2 = 0;
		matrix_line_3 = 0;
	end
    endcase
end

assign matrix_mopa_o[0] = matrix_line_0;
assign matrix_mopa_o[1] = matrix_line_1;
assign matrix_mopa_o[2] = matrix_line_2;
assign matrix_mopa_o[3] = matrix_line_3;

endmodule
